﻿using System;
using System.IO;

using SharedUtilities;

namespace Coding4Fun.Cannon.Web
{
	public partial class Default : System.Web.UI.Page
	{
		private static string _imageFolderPhysicalPath;
		readonly Serializer<string[]> _stringSerializer = new Serializer<string[]>();
		private const string ImageFolderName = "images/";
		private static readonly WebPhoto OnboardPhotoCapture = new WebPhoto();
		private static readonly WebPhoto OverheadPhotoCapture = new WebPhoto();

		private static long _currentTickCounter;
		protected void Page_Load(object sender, EventArgs e)
		{
            Response.Clear();
			if (string.IsNullOrEmpty(_imageFolderPhysicalPath))
				_imageFolderPhysicalPath = Server.MapPath(ImageFolderName);

			string command = Request.QueryString["command"];

			ParseCommand(command);

		}

		private void ParseCommand(string command)
		{
            string responseWriteData = "";
			
            bool sendCommand = string.IsNullOrEmpty(Request.QueryString["test"]);

			long newCommandTicks;
			long.TryParse(Request.QueryString["ticks"], out newCommandTicks);
			
			// did command come in after next command already executed
			if (newCommandTicks < _currentTickCounter)
				command = "__" + command; // invalidate command
			else
				_currentTickCounter = newCommandTicks;


			switch (command)
			{
				case "warmup":
					Global.Aim.Reset();
					Global.Drive.Stop();
					responseWriteData = @"<result><warmup/></result>";
					break;
				case "init":
					var panMin = Global.Settings.GetAimPanMinAngle();
					var panMax = Global.Settings.GetAimPanMaxAngle();

					var tiltMin = Global.Settings.GetAimTiltMinAngle();
					var tiltMax = Global.Settings.GetAimTiltMaxAngle();

					Global.Aim.Reset();
					Global.Drive.Stop();

					responseWriteData = string.Format(@"<result><PanMin>{0}</PanMin><PanMax>{1}</PanMax><TiltMin>{2}</TiltMin><TiltMax>{3}</TiltMax></result>"
						, panMin, panMax, tiltMin, tiltMax);
					break;
				case "capturephotos":
					if (sendCommand)
					{
						int amount;
						int interval;

						int.TryParse(Request.QueryString["amount"], out amount);
						int.TryParse(Request.QueryString["interval"], out interval);

						// if onboard query param is there, we use that else default to overhead.
						var useOnboardCamera = !string.IsNullOrEmpty(Request.QueryString["onboard"]);
						var cameraUri = new Uri(useOnboardCamera ? Global.Settings.GetDriveCameraUri() : Global.Settings.GetOverheadCameraUri());

						GetWebPhoto().StartSavingPhotos(cameraUri, _imageFolderPhysicalPath, interval, amount);
					}
					responseWriteData = @"<result><capturephotos/></result>";
					break;
				case "stopcapturingphotos":
					if (sendCommand)
					{
						GetWebPhoto().StopSavingPhotos();
					}

					responseWriteData = @"<result><stopcapturingphotos/></result>";
					break;
				case "getphotos":
                    if (sendCommand)
                    {
						Uri url;
						Uri.TryCreate(new Uri(Request.Url.GetLeftPart(UriPartial.Authority)), ResolveUrl(ImageFolderName), out url);

						var photos = WebPhoto.GetPhotos(5, _imageFolderPhysicalPath, url.ToString());
						responseWriteData = _stringSerializer.Serialize(photos); 
                    }
                    break;
				case "fire":
                    Global.PhotoTime = DateTime.Now;

                    if (sendCommand)
                    {
                        Global.Shoot.Fire();

                        var useOnboardCamera = !string.IsNullOrEmpty(Request.QueryString["onboard"]);
						var cameraUri = new Uri(Global.Settings.GetOverheadCameraUri());

                        GetWebPhoto().StartSavingPhotos(cameraUri, _imageFolderPhysicalPath, 250, 10);
                    }
					responseWriteData = @"<result>fired</result>";
					break;
				case "drive":
					if (!string.IsNullOrEmpty(Request.QueryString["power"]))
					{
						var power = int.Parse(Request.QueryString["power"]);

                        if (sendCommand)
    						Global.Drive.SetPower(power);
						
                        responseWriteData = String.Format("<result><power>{0}</power></result>", power);
					}
					else
					{
						var leftPower = int.Parse(Request.QueryString["leftpower"]);
						var rightPower = int.Parse(Request.QueryString["rightpower"]);

                        if (sendCommand)
						    Global.Drive.SetPowerByMotor(leftPower, rightPower);

                        responseWriteData = String.Format("<result><leftpower>{0}</leftpower><rightpower>{1}</rightpower></result>", leftPower, rightPower);
					}
					break;
				case "stop":
                    if (sendCommand)
        				Global.Drive.SetPower(0);

					responseWriteData = String.Format("<result><power>{0}</power></result>", 0);
					break;
				case "aim":
					var panRequest = Request.QueryString["pan"];
					var tiltRequest = Request.QueryString["tilt"];

					bool hasPan = !string.IsNullOrEmpty(panRequest);
					bool hasTilt = !string.IsNullOrEmpty(tiltRequest);
					
					double pan = 0;
					double tilt = 0;

					if(hasPan)
						hasPan = double.TryParse(panRequest, out pan);
					
					if (hasTilt)
						hasTilt = double.TryParse(tiltRequest, out tilt);
                    if (sendCommand)
                    {
                        if (hasPan && hasTilt)
                            Global.Aim.SetPanAndTiltAngles(pan, tilt);
                        else if (hasPan)
                            Global.Aim.SetPanAngle(pan);
                        else if (hasTilt)
                            Global.Aim.SetTiltAngle(tilt);
                    }

                    responseWriteData = String.Format("<result><pan>{0}</pan><tilt>{1}</tilt><panRequest>{2}</panRequest><tiltRequest>{3}</tiltRequest></result>",
                        pan, tilt, panRequest, tiltRequest);
					break;
				case "aimrandom":
                    if (sendCommand)
    					Global.Aim.SetPanAndTiltRandomly();

					responseWriteData = String.Format("<result><aimRandom/></result>");
					break;
				case "aimfiringangle":
					if (sendCommand)
						Global.Aim.SetAimFiringTiltAngle();

					responseWriteData = String.Format("<result><aimFiringAngle/></result>");
					break;
				case "twitpic":
					var fileId = Request.QueryString["fileid"];
					if (sendCommand)
					{
						var message = string.IsNullOrEmpty(Request.QueryString["tweet"]) ? "Sent by Coding4Fun Cannon" : Request.QueryString["tweet"];
						WebPhoto.UploadPicture(Global.Settings.GetTwitterUserName(), Global.Settings.GetTwitterUserName(), Path.Combine(_imageFolderPhysicalPath, fileId), message);
					}
					responseWriteData = String.Format("<result><twitpic/></result>");
					break;

                default:
					responseWriteData = string.Format("<result>unknown command at {0}</result>", DateTime.Now);
					break;
			}

			Logger.WriteToLog(command, responseWriteData);

            Response.Clear();

			Response.Write(responseWriteData);
		}

		private WebPhoto GetWebPhoto()
		{
			return (!string.IsNullOrEmpty(Request.QueryString["onboard"])) ? OnboardPhotoCapture : OverheadPhotoCapture;
		}
	}
}